package cc.mrbird.febs.pay.ali;

import cc.mrbird.febs.common.entity.PayConstant;
import cc.mrbird.febs.common.utils.OrderNoUtil;
import cc.mrbird.febs.pay.base.AbstractPayStrategy;
import cc.mrbird.febs.pay.base.PayModelFactory;
import cc.mrbird.febs.pay.enums.ALiTradeState;
import cc.mrbird.febs.pay.enums.PayType;
import cc.mrbird.febs.pay.enums.WxRefundStatus;
import cc.mrbird.febs.payment.entity.PaymentInfo;
import cc.mrbird.febs.payment.entity.RefundInfo;
import cc.mrbird.febs.payment.service.IPaymentInfoService;
import cc.mrbird.febs.payment.service.IRefundInfoService;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeCloseResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.Gson;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Objects;


/**
 * @ClassName AppPay
 * @Description 支付宝 app支付
 * @Author 狗蛋儿
 * @Date 2020/11/26 11:15
 * @Version V1.0
 **/
@Slf4j
@Service
@AllArgsConstructor
public class ALiPayAppPay extends AbstractPayStrategy {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private IPaymentInfoService iPaymentInfoServiceImpl;
    @Autowired
    private IRefundInfoService iRefundInfoServiceImpl;

    @Override
    public synchronized Object pay(Map<String, String> parameterMap) throws Exception {
        String subject = parameterMap.get("subject");
        String orderNo = parameterMap.get("orderSn");
        String totalAmount = parameterMap.get("totalAmount");

        PaymentInfo paymentInfo = iPaymentInfoServiceImpl.getPaymentInfoByOrderSn(orderNo);
        if (Objects.nonNull(paymentInfo) && StringUtils.isNotBlank(paymentInfo.getContent())) {
            return paymentInfo.getContent();
        }
        AlipayTradeAppPayResponse response = Factory.Payment.App().asyncNotify(
                stringRedisTemplate.opsForValue().get(PayConstant.SUFFIX + PayConstant.PAY_ALI_PAY_NOTIFY_URL)).pay(subject, orderNo, totalAmount);
        if (ResponseChecker.success(response)) {
            //插入支付记录
            iPaymentInfoServiceImpl.createPaymentInfo(new PaymentInfo()
                    .setPaymentType(PayType.A_LI_PAY_APP.getLabel())
                    .setUpdateTime(new Date())
                    .setCreateTime(new Date())
                    .setOrderNo(orderNo)
                    .setContent(response.getBody())
                    .setPayerTotal(new BigDecimal(totalAmount).multiply(BigDecimal.valueOf(100)).intValue())
                    .setTradeType(PayType.A_LI_PAY_APP.getTradeType())
                    .setTransactionId(iPaymentInfoServiceImpl.getTransactionId(orderNo))
                    .setTradeState(ALiTradeState.WAIT_BUYER_PAY.getType()));
            return response.getBody();
        }
        throw new RuntimeException("统一下单失败");
    }

    @Override
    public Object cancel(Map<String, String> parameterMap) throws Exception {
        String out_trade_no = parameterMap.get("orderSn");
        AlipayTradeCloseResponse response = Factory.Payment.Common().close(out_trade_no);
        if (ResponseChecker.success(response)) {
            log.info("关闭订单调用【成功】返回结果===>:{}", response.getHttpBody());
            //  ALiTradeState.TRADE_CLOSED 交易状态操作：交易关闭
            iPaymentInfoServiceImpl.close(out_trade_no);
            return out_trade_no;
        } else {
            log.info("关闭订单调用【失败】返回结果===>:{}", response.getCode());
            log.info("关闭订单调用【失败】返回结果===>:{}", response.getSubMsg());
            log.info("关闭订单调用【失败】返回结果===>:{}", response.getHttpBody());
            return null;
        }
    }


    /**
     * 根据订单查询支付记录
     *
     * @param parameterMap@return
     * @throws
     */
    @Override
    public Object queryPay(Map<String, String> parameterMap) throws Exception {
        String out_trade_no = parameterMap.get("orderSn");
        AlipayTradeQueryResponse response = Factory.Payment.Common().query(out_trade_no);
        if (ResponseChecker.success(response)) {
            log.info("查询订单调用【成功】返回结果===>:{}", response.getHttpBody());
            return out_trade_no;
        } else {
            log.info("查询订单调用【失败】返回结果===>:{}", response.getCode());
            log.info("查询订单调用【失败】返回结果===>:{}", response.getSubMsg());
            log.info("查询订单调用【失败】返回结果===>:{}", response.getHttpBody());
            return null;
        }
    }

    /**
     * 退款 支付宝同步可以 微信异步
     *
     * @param parameterMap
     * @return
     * @throws
     */
    @Override
    public synchronized Object refund(Map<String, String> parameterMap) throws Exception {
        String out_trade_no = parameterMap.get("orderSn");
        String refundAmount = parameterMap.get("refundAmount");
        String reason = parameterMap.get("reason");
        String userId = parameterMap.get("userId");

        PaymentInfo paymentInfo = iPaymentInfoServiceImpl.getOne(new LambdaQueryWrapper<PaymentInfo>().eq(PaymentInfo::getOrderNo, out_trade_no).eq(PaymentInfo::getTradeState, ALiTradeState.TRADE_SUCCESS).last(" limit 1"));
        iRefundInfoServiceImpl.createRefundInfo(new RefundInfo()
                .setRefundNo(OrderNoUtil.getOrderNum(Long.valueOf(userId)))
                .setCreateTime(new Date())
                .setOrderNo(out_trade_no)
                .setTotalFee(paymentInfo.getPayerTotal())
                .setRefund(Integer.parseInt(refundAmount) * 100)
                .setUpdateTime(new Date())
                .setRefundStatus(WxRefundStatus.PROCESSING.getType())
                .setReason(reason)
                .setRefundId(paymentInfo.getTransactionId()));

        AlipayTradeRefundResponse response = Factory.Payment.Common().refund(out_trade_no, refundAmount);
        if (ResponseChecker.success(response)) {
            log.info("退款订单调用【成功】返回结果===>:{}", response.getHttpBody());
            // ALiTradeState.TRADE_FINISHED 交易结束，不可退款
            iRefundInfoServiceImpl.updateRefundContent(out_trade_no, response.getHttpBody(), WxRefundStatus.SUCCESS.getType());
            return out_trade_no;
        } else {
            log.info("退款订单调用【失败】返回结果===>:{}", response.getCode());
            log.info("退款订单调用【失败】返回结果===>:{}", response.getSubMsg());
            log.info("退款订单调用【失败】返回结果===>:{}", response.getHttpBody());
            iRefundInfoServiceImpl.updateRefundContent(out_trade_no, response.getHttpBody(), "");
            throw new RuntimeException("退款订单调用【失败】");
        }
    }

    /**
     * 退款查询
     *
     * @param parameterMap
     * @return
     * @throws
     */
    @Override
    public Object queryRefund(Map<String, String> parameterMap) throws Exception {
        String out_trade_no = parameterMap.get("orderSn");
        AlipayTradeFastpayRefundQueryResponse response = Factory.Payment.Common().queryRefund(out_trade_no, out_trade_no);
        if (ResponseChecker.success(response)) {
            log.info("查询订单调用【成功】返回结果===>:{}", response.getHttpBody());
            return out_trade_no;
        } else {
            log.info("退款查询订单调用【失败】返回结果===>:{}", response.getCode());
            log.info("退款查询订单调用【失败】返回结果===>:{}", response.getSubMsg());
            log.info("退款查询订单调用【失败】返回结果===>:{}", response.getHttpBody());
             throw new RuntimeException("退款订单调用【失败】");
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        PayModelFactory.register(PayType.A_LI_PAY_APP.getCode(), this);
    }
}
